package cn.bluech.lib.appbase;

import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.os.Build;
import android.text.TextUtils;
import android.util.Log;

import java.io.File;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.io.Writer;
import java.lang.reflect.Field;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;

import cn.bluech.lib.utils.FileUtils;

/**
 * Description:
 * Create by Codeant on 2019/9/3.
 */
public class ExceptionCollector {
    private static final String TAG = "Exception";
    private static ExceptionCollector instance;

    private Context context;
    private String storageDir;

    private Listener listener;
    private DateFormat dateFormat;

    public static ExceptionCollector getInstance() {
        if(null!=instance)
            return instance;
        synchronized (ExceptionCollector.class){
            if(null==instance)
                instance = new ExceptionCollector();
        }
        return instance;
    }

    private ExceptionCollector(){
        dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault());
    }

    public ExceptionCollector init(Context context){
        this.context = context;
        // 未捕获的异常管理
        Thread.setDefaultUncaughtExceptionHandler((thread, throwable) -> {
            // 输出到 Logcat
            Log.e(TAG,throwable.getLocalizedMessage(),throwable);

            // 保存成文件
            saveException(getSystemInfo(),throwable);

            if(null!=listener)
                listener.onCrashExit(throwable);
        });

        return this;
    }

    public ExceptionCollector setListener(Listener listener) {
        this.listener = listener;

        return this;
    }

    public ExceptionCollector setStorageDir(String storageDir) {
        this.storageDir = storageDir;

        return this;
    }

    private Map<String,String> getSystemInfo(){
        Map<String,String> infos = new HashMap<>();

        // 版本信息
        try {
            PackageManager manager = context.getPackageManager();
            PackageInfo packageInfo = manager.getPackageInfo(context.getPackageName(),PackageManager.GET_ACTIVITIES);
            infos.put("versionName",null!=packageInfo.versionName?packageInfo.versionName:"null");
            infos.put("versionCode",packageInfo.versionCode+"");
        } catch (Exception e) {
            e.printStackTrace();
        }

        // 设备信息
        Field[] fields = Build.class.getDeclaredFields();
        for(Field field:fields){
            try{
                field.setAccessible(true);
                infos.put(field.getName(),field.get(null).toString());
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        return infos;
    }

    private void saveException(Map<String,String> infos,Throwable throwable){
        StringBuilder sb = new StringBuilder();
        for(Map.Entry<String,String> entry : infos.entrySet()){
            sb.append(entry.getKey()).append('=').append(entry.getValue()).append("\r\n");
        }
        sb.append("\r\n");
        sb.append(throwable.getLocalizedMessage()).append("\r\n");

        Writer writer = new StringWriter();
        PrintWriter printWriter = new PrintWriter(writer);
        throwable.printStackTrace(printWriter);
        Throwable cause = throwable.getCause();
        while (null!=cause){
            cause.printStackTrace(printWriter);
            cause = cause.getCause();
        }
        printWriter.close();

        sb.append(writer.toString());

        String fileName = "crash-"+dateFormat.format(new Date())+".txt";
        if(TextUtils.isEmpty(storageDir))
            return;
        String filePath = storageDir.endsWith(File.separator)?storageDir+fileName:storageDir+File.separator+fileName;
        FileUtils.write(filePath,sb.toString().getBytes());
    }




    public interface Listener{
        /**
         * 系统崩溃，马上退出(在这里回收一下Activity)
         */
        void onCrashExit(Throwable throwable);
    }
}
